#include "RR.h"
#include <stdio.h>
#include <stdlib.h>

/**
 * 函数: calculateTimes
 * 功能: 根据时间片轮转调度算法计算每个进程的完成时间、周转时间和等待时间
 *
 * 参数:
 *  - processes: 指向包含多个进程信息的数组
 *  - n: 进程数量
 *  - time_slice: 时间片长度
 *
 * 描述:
 *  计算进程的完成时间，周转时间和等待时间并存在结构体中即可
 */

// int is_x_in_arr(int* arr, int size, int x)
// {
//   for (int i = 0; i < size; ++i)
//   {
//     if (arr[i] == x)
//     {
//       return 1;
//     }
//   }
//   return 0;
// }

// void sort_ready_queue(Process *processes, int* ready_queue, int ready_count)
// {

// }

// push the top process index to the last one
void maintain_queue(int* ready_queue, int ready_count)
{
  for(int i = 0; (i < ready_count-1) && (ready_queue[i+1] != -1) ; i++)
  {
      int temp = ready_queue[i];
      ready_queue[i] = ready_queue[i+1];
      ready_queue[i+1] = temp;
  }  
}

void receive_arrived_processes(int ready_queue[], int* ready_count, Process* processes, 
                                int is_in_queue[], int* is_new_process_arrive, int n, int time)
{
  if (*ready_count < n)
  {
    for (int i = 0; i < n; ++i)
    {
      if (processes[i].arrival_time <= time && !is_in_queue[i] && processes[i].remaining_time) 
      {
        ready_queue[*ready_count] = i;
        is_in_queue[i] = 1;
        *is_new_process_arrive = 1;
        *ready_count += 1;
      }
    }
    
    if (*ready_count > n)
    {
      printf("ERROR: ready queue size > total process number!\n");
    }
  }
}


void
calculateTimes (Process *processes, int n, int time_slice)
{
  // TODO
  int num_finished_proc = 0;
  int ind = 0;
  int time = 0;
  int ready_queue[n];
  // int top = 0;
  int ready_count = 0;
  int is_new_process_arrive = 0;
  int is_in_queue[n];
  // Process* cur_proc = NULL;

  for (int i = 0; i < n; ++i)
  {
    is_in_queue[i] = 0;
    ready_queue[i] = -1;
  }

  while(num_finished_proc < n)
  {

    // 1. push ready-to-serve process into ready_queue

    receive_arrived_processes(ready_queue, &ready_count, processes, 
                                is_in_queue, &is_new_process_arrive, n, time);

    // 1.5 sort the ready queue
    // if (is_new_process_arrive)
    // {
    //   sort_ready_queue();
    // }

    // 2. if the time slice used up OR the process is done, choose a new process from the ready queue to serve
    

    ind = ready_queue[0];
    maintain_queue(ready_queue, ready_count);
    --ready_count;

    // 3. run the proess 
    // processes[ind].remaining_time--;
    // ++time;
    if (processes[ind].remaining_time <= time_slice)
    {
      time += processes[ind].remaining_time;
      processes[ind].completion_time = time;
      processes[ind].turnaround_time = processes[ind].completion_time - processes[ind].arrival_time;
      processes[ind].waiting_time = processes[ind].turnaround_time - processes[ind].burst_time;
      if (processes[ind].waiting_time < 0)
      {
        processes[ind].waiting_time = 0;
      }
      processes[ind].remaining_time = 0;

    
      receive_arrived_processes(ready_queue, &ready_count, processes, 
                                is_in_queue, &is_new_process_arrive, n, time);


      // one process done
      num_finished_proc++;
    }

    // if take the full time slice can't finish current process, 
    // push the process into the last of the ready queue
    // and receive arrived processes
    else
    {
      processes[ind].remaining_time -= time_slice;
      time += time_slice;

      receive_arrived_processes(ready_queue, &ready_count, processes, 
                            is_in_queue, &is_new_process_arrive, n, time);

      // add the imcomplete process index into the ready_queue
      ready_queue[ready_count++] = ind;
    }

  }
}
